/*
 * Copyright (c) 2009-2013 EvTech Project
 * All rights reserved.
 * 
 * This file is part of Symbol Matching.
 *
 * Symbol Matching is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 *
 * Symbol Matching is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Symbol Matching.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package fi.honkalampisaatio.reaktiopeli.game;


import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

import javax.sound.sampled.Clip;
import javax.swing.AbstractButton;
import javax.swing.JPanel;

import fi.honkalampisaatio.game.utilities.MediaLoader;
import fi.honkalampisaatio.game.utilities.TextToSpeech;
import fi.honkalampisaatio.reaktiopeli.target.TargetEvent;
import fi.honkalampisaatio.reaktiopeli.target.TargetEventListener;
import fi.honkalampisaatio.reaktiopeli.xml.ChoiceButton;
import fi.honkalampisaatio.reaktiopeli.xml.QAElement;
import fi.honkalampisaatio.reaktiopeli.xml.Question;

public class ChoicePanel extends JPanel implements MouseListener  {
	private static final long serialVersionUID = -7051651068396480933L;
	
	private ArrayList<TargetButton> buttons;
	private ArrayList<QuestionElement> questions;
	private int maxShownButtonsCount;
	private Random rnd = new Random();
	private final int MAX_IMAGE_WIDTH = 800;
	private final int MAX_IMAGE_HEIGHT = 800;
	private int     shownButtonCount;	
	private double  maxWidth;
	private int     whoIsUsingTheMouse=0;
	
	private TargetEventListener listener = null;
	
	public ChoicePanel() {
		this.buttons         = new ArrayList<TargetButton>();
		this.questions       = new ArrayList<QuestionElement>();
		maxShownButtonsCount = 0;
		
		this.addMouseListener(this);		
	}

	 public void mouseClicked (MouseEvent e) { } 
	 public void mouseEntered (MouseEvent e) { } 
	 public void mouseExited  (MouseEvent e) { }
	 public void mouseReleased(MouseEvent e) { }
	 
	 /* Handle the users mouse press and pass it to fire event same as if the user pressed keyboard */
	 public void mousePressed (MouseEvent e) {		 
			 
		 	 int pressedButtonNumber  = getButtonNroOfPressedCoordinate( e.getX(),  e.getY() );
		 	 //TargetEvent     tEvent  = new TargetEvent(this, pressedButtonNumber, TargetEvent.TYPE.PRESS);
		 	 
		 	 if (whoIsUsingTheMouse  == GamePanel.PLAYER_1) { // Draw everything only if we'r using the mouse
		 		TargetEvent     tEvent= new TargetEvent(this, pressedButtonNumber, TargetEvent.TYPE.PRESS, TargetEvent.PLAYER.PLAYER_1);
			 	fireTargetEvent(tEvent);
		 	 }
		 	if (whoIsUsingTheMouse  == GamePanel.PLAYER_2) { // Draw everything only if we'r using the mouse
		 		TargetEvent     tEvent= new TargetEvent(this, pressedButtonNumber, TargetEvent.TYPE.PRESS, TargetEvent.PLAYER.PLAYER_2); // +3 because it's the later part of the buttons for player 2 usually..
			 	fireTargetEvent(tEvent);
		 	 }
			 
	 } 
	 
	public void setMouseUser(int mouseUser) {
		whoIsUsingTheMouse = mouseUser;
	}
	 
	public void addTargetEventListener(TargetEventListener listener) {
			this.listener = listener;
	}
		
	public void removeTargetEventListener(TargetEventListener listener) {
		if(this.listener==listener) {
			listener=null;
		}
	}
		
	private void fireTargetEvent(TargetEvent e) {		
		if(listener!=null) {
			listener.targetEventOccurred(e);
		}
	}

	 // Returns the pressed button by coordinate. use for example with mouse coordinates
	 int getButtonNroOfPressedCoordinate(int px, int py) {		 
		 int theButton;
		 theButton = (int)(px / maxWidth); 
		 return theButton;
	 }
	
	public void setChoiceQuestions(ArrayList<Question> choices) {
		if(choices==null || choices.isEmpty()) {
			return;
		}
		this.questions.clear();
		Iterator<Question> choicesIterator = choices.iterator();
		while(choicesIterator.hasNext()) {
			Question choice = choicesIterator.next();
			QuestionElement qe = new QuestionElement();
			qe.setAnswer(getQuestionMedia(choice.getAnswer()));
			qe.setQuestionList(getQuestionMediaList(choice.getQuestionList()));
			this.questions.add(qe);
		}
	}
	
	private MediaElement getQuestionMedia(QAElement qa) {
		MediaElement me = new MediaElement();
		Clip sound = null;
		me.setImage(MediaLoader.createImage(qa.getImage(), 
				MAX_IMAGE_HEIGHT, MAX_IMAGE_WIDTH));
		me.setText(qa.getText());
		me.setInstruction(qa.getInstruction());
		if(qa.getSpeech()!=null) {
			sound = TextToSpeech.getInstance().getSpeechClip(qa.getSpeech(), qa.getSpeechFilePath());
		}
		else {
			sound = MediaLoader.createSoundClip(qa.getSound());
		}
		me.setSound(sound);
		
		return me;
	}

	private ArrayList<MediaElement> getQuestionMediaList(
			ArrayList<QAElement> questionList) {
		ArrayList<MediaElement> retList = new ArrayList<MediaElement>();
		if(questionList==null || questionList.isEmpty()) {
			return null;
		}
		Iterator<QAElement> questionIterator = questionList.iterator();
		while(questionIterator.hasNext()) {
			MediaElement me = getQuestionMedia(questionIterator.next());
			retList.add(me);
		}
		return retList;
	}

	public BufferedImage getButtonImage(int i) {
		return buttons.size()>i ? buttons.get(i).getOriginalImage() : null;
	}

	public void paintComponent(Graphics g) {
        super.paintComponent(g);     
        
        Graphics2D g2 = (Graphics2D) g;
		Rectangle2D rc = null;
		shownButtonCount = maxShownButtonsCount>buttons.size()?buttons.size():maxShownButtonsCount;
		double maxHeight;
		maxHeight = this.getHeight();
		maxWidth = shownButtonCount>0?(this.getWidth()/shownButtonCount):this.getWidth();
		float fontSize = 144;
		 // Draw everything only if we'r using the mouse
		
        for(int i=0;i<shownButtonCount;i++) {
      	String text = buttons.get(i).getAnswer().getText();
      	if(text==null) {
      		text = " ";
      	}
      	g2.setFont(getFont().deriveFont(fontSize));
      	
      	rc = g2.getFontMetrics().getStringBounds(text, g2);
      	if(rc.getHeight()>maxHeight) {
      		fontSize = (int)(fontSize*maxHeight/rc.getHeight());
          	g2.setFont(getFont().deriveFont(fontSize));
      	}
      	
      	rc = g2.getFontMetrics().getStringBounds(text, g2);
      	if(rc.getWidth()>maxWidth) {
      		fontSize = (int)(fontSize*maxWidth/rc.getWidth());
          	g2.setFont(getFont().deriveFont(fontSize));
      	}

      	rc = g2.getFontMetrics().getStringBounds(text, g2);
      }
      int x = 0;
      for(int i=0;i<shownButtonCount;i++) {
      	String text = buttons.get(i).getAnswer().getText();
      	if(text==null) {
      		text = " ";
      	}
      	rc = g2.getFontMetrics().getStringBounds(text, g2);
      	BufferedImage buffImg;
      	buffImg = buttons.get(i).getOriginalImage();
      	if(buffImg != null) {
      		int imgW, imgH;
      		imgH = (int)(maxHeight);
      		imgW = buffImg.getWidth() * imgH / buffImg.getHeight();
      		if(imgW > maxWidth)
      		{
          		imgW = (int)(maxWidth);
          		imgH = buffImg.getHeight() * imgW / buffImg.getWidth();
      		}
          	g2.drawImage(buffImg, (int)(x + (maxWidth-imgW)/2), (int)((maxHeight-imgH)/2), imgW, imgH, null);
      	}
      	if(buttons.get(i).getBgColor() != null)
      	{
      		Color origColor = g2.getColor();
      		g2.setColor(buttons.get(i).getBgColor());
      		g2.fillRect(x, 0, (int)(maxWidth-2), (int)maxHeight-1);
      		g2.setColor(origColor);
      	}
      	g2.drawRect(x, 0, (int)(maxWidth-2), (int)maxHeight-1);
      	g2.drawString(text, (int)(x+(maxWidth-rc.getWidth())/2), 
      			(int)((maxHeight+rc.getHeight())/2-g2.getFontMetrics().getDescent()));
      	x = x + (int)maxWidth;        	
      }
		
	  
		
	}

	public void setButtons(ArrayList<ChoiceButton> choiceButtons) {
		removeButtons();
		if(choiceButtons==null) {
			return;
		}
		for(int i=0; i<choiceButtons.size();i++) {
			ChoiceButton buttonData = choiceButtons.get(i);
			TargetButton button = createButton(buttonData, i);
			if(button!=null) {
				this.buttons.add(button);
				this.add(button);
			}
		}
		this.repaint();
	}
	
	private TargetButton createButton(ChoiceButton buttonData, int i) {
		TargetButton button = new TargetButton(i);
		if(buttonData!=null) {
			button.setIconAndImage(buttonData.getImage(), buttonData.getBgColor());
		}
		if(buttonData!=null && buttonData.getQuestionList()!=null) {
			ArrayList<MediaElement> questionList = getQuestionMediaList(buttonData.getQuestionList());
			button.setQuestions(questionList);
		}

		button.setFocusable(false);
		button.setVerticalTextPosition(AbstractButton.BOTTOM);
		button.setHorizontalTextPosition(AbstractButton.CENTER);
		button.setVisible(false);
		return button;
	}

	private void removeButtons() {
		this.removeAll();
		this.buttons.clear();
	}

	public void setTarget(int rightAnswer) {
		buttons.get(rightAnswer).setOn();
	}
	
	public void clearAllTargets() {
		Iterator<TargetButton> it = buttons.iterator();
		while(it.hasNext()) {
			it.next().setOff();
		}
	}

	public void setMaxShownButtonsCount(int maxShownButtonsCount) {
		this.maxShownButtonsCount = maxShownButtonsCount;
	}

	public int getMaxShownButtonsCount() {
		return maxShownButtonsCount;
	}

	public MediaElement getButtonQuestion(int i) {
		return buttons.size()>i ? buttons.get(i).getQuestion() : null;
	}

	public ArrayList<TargetButton> getButtons() {
		return buttons;
	}

	public void shuffleChoices() {
		int shownButtonCount = maxShownButtonsCount>buttons.size()?buttons.size():maxShownButtonsCount;
		
		if(shownButtonCount>=this.questions.size()) {
			for(int i=0;i<this.questions.size();i++) {
				TargetButton button = this.buttons.get(i);
				QuestionElement qa = this.questions.get(i);
				button.setAnswer(qa.getAnswer());
				button.setQuestions(qa.getQuestionList());
			}
		}
		else {
			ArrayList<Integer> indexList = new ArrayList<Integer>();
			for(int i=0;i<this.questions.size();i++) {
				indexList.add(i);
			}
			
			for(int i=0;i<shownButtonCount;i++) {
				TargetButton button = this.buttons.get(i);
				int rndIndex = rnd.nextInt(indexList.size());
				QuestionElement qa = this.questions.get(indexList.get(rndIndex));
				indexList.remove(rndIndex);
				button.setAnswer(qa.getAnswer());
				button.setQuestions(qa.getQuestionList());
			}
		}
		this.repaint();
	}

	
	public void reset() {
		this.buttons.clear();
		this.questions.clear();
		maxShownButtonsCount = 0;
	}

	public String getButtonName(int i) {
		String name = "";
		TargetButton button = this.buttons.get(i);
		if(button!=null) {
			name = button.getName();
		}
		return name;
	}

	public ArrayList<BufferedImage> getCurrentOriginalImages() {
		ArrayList<BufferedImage> retArray = new ArrayList<BufferedImage>();
		int shownButtonCount = maxShownButtonsCount>buttons.size()?buttons.size():maxShownButtonsCount;
		for(int i=0;i<shownButtonCount;i++) {
			retArray.add(this.buttons.get(i).getOriginalImage());
		}
		return retArray;
	}

}
